package simpleParticleSystemPackage;

import javax.media.j3d.*;
import com.sun.j3d.utils.geometry.*;
import java.util.Random;
import javax.vecmath.Vector3f;
import javax.vecmath.Point3f;

/**
* Eine Implementierung des Interface ISimpleParticleCreator fuer
* das Wunderkerzenbeispiel. Ein Partikel besteht aus mehreren
* zufaellig positionierten Funken in einem quaderfoermigen
* Bereich. Die einzelnen Funken werden als Dreiecke
* erzeugt. Es steht auch eine Methode zur Verfuegung, mit
* der Funken in Form von Tetraedern erzeugt werden koennen.
* Diese Methode wird hier aber nicht benutzt.
*
* @author Frank Klawonn
* Letzte Aenderung 1.8.2008
*
*/
public class LineOfSparksCreator implements ISimpleParticleCreator
{

  //Zur Festlegung der Groesse eines einzelnen Funkens
  public float radius;

  //Die Appearance der Funken
  public Appearance app;

  //Anzahl der Funken, die ein Partikel bilden
  public int numberOfSparks;

  //Hoehe des quaderfoermigen Bereichs
  public float length;

  //Halbe Hoehe des Zylinders
  public float halfLength;

  //Halbe Dicke und Breite des quaderfoermigen Bereichs
  float thickness;

  //Zur Erzeugung der zufaelligen Positionen der Funken im quaderfoermigen Bereich
  public Random prng;


  /**
  * Konstruktor
  *
  * @param r   Zur Festlegung der Groesse eines einzelnen Funkens
  * @param a   Die Appearance fuer die Funken
  * @param n   Anzahl der Funken, die ein Partikel bilden
  * @param l   Hoehe des quaderfoermigen Bereichs, in dem die Funken erzeugt werden
  * @param t   Halbe Dicke und Breite des quaderfoermigen Bereichs
  */
  public LineOfSparksCreator(float r, Appearance a, int n, float l, float t)
  {
    radius = r;
    app = a;
    numberOfSparks = n;
    length = l;
    halfLength = length/2;
    thickness = t;

    prng = new Random();
  }


  /**
  * Implementierung der entsprechenden Methode des Interface.
  */
  public  TransformGroup getNextParticle()
  {
    //Ein Array vonTransformationsgruppen, fuer jeden Funke eine Transformationsgruppe
    TransformGroup[] tgArray = new TransformGroup[numberOfSparks];

    //Die Transformationsgruppe, die die Funken zu einem Partikel zusammenfasst
    TransformGroup tgSparks = new TransformGroup();

    //Erzeugung der einzelnen Funken und Zusammenfassung in einer Transformationsgruppe
    for (int i=0; i<tgArray.length; i++)
    {
      Transform3D tfPos = new Transform3D();
      tfPos.setTranslation(new Vector3f(thickness*(prng.nextFloat()-0.5f),
                                        prng.nextFloat()*length - halfLength,
                                        thickness*(prng.nextFloat()-0.5f)));
      tgArray[i] = new TransformGroup(tfPos);

      Shape3D tet = this.makeTriangle();
      //Wenn die Funken durch Tetraeder statt durch Dreiecke modelliert
      //werden sollen, kann die folgende Methode statt this.makeTriangle();
      //verwendet werden.
      //Shape3D tet = this.makeTetrahedron();

      tgArray[i].addChild(tet);
      tgSparks.addChild(tgArray[i]);
    }


      return(tgSparks);

  }


  /**
  * Methode zur Erzeugung eines Funkens in Form eines Tetraeders
  *
  * @return  Der Funken als Shape
  */
  public Shape3D makeTetrahedron()
  {
    float rcos30 = radius*((float) Math.sqrt(0.75));
    float rsin30 = radius*0.5f;
    //Die vier Ecken des Tetraeders
    Point3f[] tetrahedronCoordinates =
    {
      new Point3f(rcos30,-rsin30,0.0f),
      new Point3f(-rcos30,-rsin30,0.0f),
      new Point3f(0.0f,0.0f,-radius),
      new Point3f(0.0f,radius,0.0f)
    };


    //Die vier Dreiecke des Tetraeders
    int coordIndices[] =
      {
        0,3,1,
        0,2,3,
        0,1,2,
        1,3,2
      };




    GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);
    gi.setCoordinates(tetrahedronCoordinates);
    gi.setCoordinateIndices(coordIndices);
    NormalGenerator ng = new NormalGenerator();
    ng.generateNormals(gi);
    GeometryArray te = gi.getGeometryArray();

    //Erzeugung des Tetraeders als Shape
    Shape3D tetrahedron = new Shape3D(te,app);

    return(tetrahedron);

  }



  /**
  * Methode zur Erzeugung eines Funkens in Form eines
  * von beiden Seiten sichtbaren Dreiecks
  *
  * @return  Der Funken als Shape
  */
  public Shape3D makeTriangle()
  {
    Point3f[] triangleCoordinates =
    {
      new Point3f(radius,0.0f,0.0f),
      new Point3f(0.0f,radius,0.0f),
      new Point3f(0.0f,0.0f,radius)
    };


    //Vorder- und Rueckseite des Dreiecks
    int coordIndices[] =
      {
        0,1,2,
        0,2,1
      };




    GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY);
    gi.setCoordinates(triangleCoordinates);
    gi.setCoordinateIndices(coordIndices);
    NormalGenerator ng = new NormalGenerator();
    ng.generateNormals(gi);
    GeometryArray te = gi.getGeometryArray();

    //Erzeugung des Dreiecks als Shape
    Shape3D triangle = new Shape3D(te,app);

    return(triangle);

  }


}
